A C++ compiler will allow a Derived* to masquerade as a Base*, since a Derived object is a kind of a Base object. However passing a Derived** as a Base** (or otherwise trying to convert a Derived** to a Base**) is (correctly) flagged as an error.
An array of Deriveds is-NOT-a-kind-of-an array of Bases. I like to use the following example in my C++ training sessions:
'A Bag of Apples is *NOT* a Bag of Fruit'
Suppose a 'Bag<Apple>' could be passed to a function taking a Bag<Fruit> such as 'f(Bag<Fruit>& b)'. But 'f()' can insert *any* kind of Fruit into the Bag. Imagine the surprise on the caller's face when he gets the Bag back only to find it has a Banana in it!
Here's another example I use:
A ParkingLot of Car is-NOT-a-kind-of-a ParkingLot of Vehicle
(otherwise you could pass a ParkingLot<Car>* as a ParkingLot<Vehicle>*, and the called fn could park an EighteenWheeler in a ParkingLot designed for Cars!)
These improper things are violations of 'contravariance' (that's the scientific glue that holds OOP together). C++ enforces contravariance, so you should trust your compiler at moments like these. Contravariance is more solid than our fickle intuition.